home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / gedit-2 / plugins / snippets / Placeholder.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  25.2 KB  |  678 lines

  1. #    Gedit snippets plugin
  2. #    Copyright (C) 2005-2006  Jesse van den Kieboom <jesse@icecrew.nl>
  3. #
  4. #    This program is free software; you can redistribute it and/or modify
  5. #    it under the terms of the GNU General Public License as published by
  6. #    the Free Software Foundation; either version 2 of the License, or
  7. #    (at your option) any later version.
  8. #
  9. #    This program is distributed in the hope that it will be useful,
  10. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #    GNU General Public License for more details.
  13. #
  14. #    You should have received a copy of the GNU General Public License
  15. #    along with this program; if not, write to the Free Software
  16. #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17.  
  18. import traceback
  19. import re
  20. import os
  21. import sys
  22. import signal
  23. import select
  24. import locale
  25. import subprocess
  26. from SubstitutionParser import SubstitutionParser
  27. import gobject
  28.  
  29. from Helper import *
  30.  
  31. # These are places in a view where the cursor can go and do things
  32. class Placeholder:
  33.         def __init__(self, view, tabstop, defaults, begin):
  34.                 self.ok = True
  35.                 self.done = False
  36.                 self.buf = view.get_buffer()
  37.                 self.view = view
  38.                 self.has_references = False
  39.                 self.mirrors = []
  40.                 self.leave_mirrors = []
  41.                 self.tabstop = tabstop
  42.                 self.set_default(defaults)
  43.                 self.prev_contents = self.default
  44.                 self.set_mark_gravity()
  45.                 
  46.                 if begin:
  47.                         self.begin = self.buf.create_mark(None, begin, self.mark_gravity[0])
  48.                 else:
  49.                         self.begin = None
  50.                 
  51.                 self.end = None
  52.         
  53.         def __str__(self):
  54.                 return '%s (%s)' % (str(self.__class__), str(self.default))
  55.  
  56.         def set_mark_gravity(self):
  57.                 self.mark_gravity = [True, False]
  58.  
  59.         def set_default(self, defaults):
  60.                 if not defaults:
  61.                         self.default = None
  62.                         return
  63.  
  64.                 for d in defaults:
  65.                         d = self.expand_environment(d)
  66.                         
  67.                         if d != '':
  68.                                 self.default = d
  69.                                 return
  70.  
  71.                 self.default = None
  72.         
  73.         def literal(self, s):
  74.                 return repr(s)
  75.                 
  76.         def format_environment(self, s):
  77.                 return s
  78.  
  79.         def re_environment(self, m):
  80.                 if m.group(1) or not m.group(2) in os.environ:
  81.                         return '$' + m.group(2)
  82.                 else:
  83.                         return self.format_environment(os.environ[m.group(2)])
  84.  
  85.         def expand_environment(self, text):
  86.                 if not text:
  87.                         return text
  88.  
  89.                 return re.sub('(\\\\)?\\$([A-Z_]+)', self.re_environment, text)
  90.         
  91.         def get_iter(self, mark):
  92.                 if mark and not mark.get_deleted():
  93.                         return self.buf.get_iter_at_mark(mark)
  94.                 else:
  95.                         return None
  96.  
  97.         def begin_iter(self):
  98.                 return self.get_iter(self.begin)
  99.         
  100.         def end_iter(self):
  101.                 return self.get_iter(self.end)
  102.         
  103.         def run_last(self, placeholders):
  104.                 begin = self.begin_iter()
  105.                 self.end = self.buf.create_mark(None, begin, self.mark_gravity[1])
  106.  
  107.                 if self.default:
  108.                         insert_with_indent(self.view, begin, self.default, False, self)
  109.         
  110.         def remove(self, force = False):
  111.                 if self.begin and not self.begin.get_deleted():
  112.                         self.buf.delete_mark(self.begin)
  113.                 
  114.                 if self.end and not self.end.get_deleted():
  115.                         self.buf.delete_mark(self.end)
  116.                 
  117.         # Do something on beginning this placeholder
  118.         def enter(self):
  119.                 if not self.begin or self.begin.get_deleted():
  120.                         return
  121.  
  122.                 self.buf.move_mark(self.buf.get_insert(), self.begin_iter())
  123.  
  124.                 if self.end:
  125.                         self.buf.move_mark(self.buf.get_selection_bound(), self.end_iter())
  126.                 else:
  127.                         self.buf.move_mark(self.buf.get_selection_bound(), self.begin_iter())
  128.         
  129.         def get_text(self):
  130.                 if self.begin and self.end:
  131.                         biter = self.begin_iter()
  132.                         eiter = self.end_iter()
  133.                         
  134.                         if biter and eiter:
  135.                                 return self.buf.get_text(self.begin_iter(), self.end_iter())
  136.                         else:
  137.                                 return ''
  138.                 else:
  139.                         return ''
  140.         
  141.         def add_mirror(self, mirror, onleave = False):
  142.                 mirror.has_references = True
  143.  
  144.                 if onleave:
  145.                         self.leave_mirrors.append(mirror)
  146.                 else:
  147.                         self.mirrors.append(mirror)
  148.  
  149.         def set_text(self, text):
  150.                 if self.begin.get_deleted() or self.end.get_deleted():
  151.                         return
  152.  
  153.                 # Set from self.begin to self.end to text!
  154.                 self.buf.begin_user_action()
  155.                 # Remove everything between self.begin and self.end
  156.                 begin = self.begin_iter()
  157.                 self.buf.delete(begin, self.end_iter())
  158.  
  159.                 # Insert the text from the mirror
  160.                 insert_with_indent(self.view, begin, text, True, self)
  161.                 self.buf.end_user_action()
  162.                 
  163.                 self.update_contents()
  164.  
  165.         def update_contents(self):
  166.                 prev = self.prev_contents
  167.                 self.prev_contents = self.get_text()
  168.                 
  169.                 if prev != self.get_text():
  170.                         for mirror in self.mirrors:
  171.                                 if not mirror.update(self):
  172.                                         return
  173.  
  174.         def update_leave_mirrors(self):
  175.                 # Notify mirrors
  176.                 for mirror in self.leave_mirrors:
  177.                         if not mirror.update(self):
  178.                                 return
  179.  
  180.         # Do something on ending this placeholder
  181.         def leave(self):
  182.                self.update_leave_mirrors()
  183.  
  184.         def find_mirrors(self, text, placeholders):
  185.                 mirrors = []
  186.                 
  187.                 while (True):
  188.                         m = re.search('(\\\\)?\\$(?:{([0-9]+)}|([0-9]+))', text)
  189.                         
  190.                         if not m:
  191.                                 break
  192.                         
  193.                         # Skip escaped mirrors
  194.                         if m.group(1):
  195.                                 text = text[m.end():]
  196.                                 continue
  197.  
  198.                         tabstop = int(m.group(2) or m.group(3))
  199.  
  200.                         if tabstop in placeholders:
  201.                                 if not tabstop in mirrors:
  202.                                         mirrors.append(tabstop)
  203.  
  204.                                 text = text[m.end():]
  205.                         else:
  206.                                 self.ok = False
  207.                                 return None
  208.                 
  209.                 return mirrors 
  210.  
  211. # This is an placeholder which inserts a mirror of another Placeholder        
  212. class PlaceholderMirror(Placeholder):
  213.         def __init__(self, view, tabstop, begin):
  214.                 Placeholder.__init__(self, view, -1, None, begin)
  215.                 self.mirror_stop = tabstop
  216.  
  217.         def update(self, mirror):
  218.                 self.set_text(mirror.get_text())
  219.                 return True
  220.  
  221.         def run_last(self, placeholders):
  222.                 Placeholder.run_last(self, placeholders)
  223.  
  224.                 if self.mirror_stop in placeholders:
  225.                         mirror = placeholders[self.mirror_stop]
  226.                         
  227.                         mirror.add_mirror(self)
  228.                         
  229.                         if mirror.default:
  230.                                 self.set_text(mirror.default)
  231.                 else:
  232.                         self.ok = False
  233.  
  234. # This placeholder indicates the end of a snippet
  235. class PlaceholderEnd(Placeholder):
  236.         def __init__(self, view, begin, default):
  237.                 Placeholder.__init__(self, view, 0, default, begin)
  238.         
  239.         def run_last(self, placeholders):
  240.                 Placeholder.run_last(self, placeholders)
  241.                 
  242.                 # Remove the begin mark and set the begin mark
  243.                 # to the end mark, this is needed so the end placeholder won't contain
  244.                 # any text
  245.                 
  246.                 if not self.default:
  247.                         self.mark_gravity[0] = False
  248.                         self.buf.delete_mark(self.begin)
  249.                         self.begin = self.buf.create_mark(None, self.end_iter(), self.mark_gravity[0])
  250.  
  251.         def enter(self):
  252.                 if self.begin and not self.begin.get_deleted():
  253.                         self.buf.move_mark(self.buf.get_insert(), self.begin_iter())
  254.                 
  255.                 if self.end and not self.end.get_deleted():
  256.                         self.buf.move_mark(self.buf.get_selection_bound(), self.end_iter())
  257.                 
  258.         def leave(self):
  259.                 self.enter()                        
  260.  
  261. # This placeholder is used to expand a command with embedded mirrors        
  262. class PlaceholderExpand(Placeholder):
  263.         def __init__(self, view, tabstop, begin, s):
  264.                 Placeholder.__init__(self, view, tabstop, None, begin)
  265.  
  266.                 self.mirror_text = {0: ''}
  267.                 self.timeout_id = None
  268.                 self.cmd = s
  269.                 self.instant_update = False
  270.  
  271.         def __str__(self):
  272.                 s = Placeholder.__str__(self)
  273.                 
  274.                 return s + ' ' + self.cmd
  275.  
  276.         def get_mirrors(self, placeholders):
  277.                 return self.find_mirrors(self.cmd, placeholders)
  278.                 
  279.         # Check if all substitution placeholders are accounted for
  280.         def run_last(self, placeholders):
  281.                 Placeholder.run_last(self, placeholders)
  282.  
  283.                 self.ok = True
  284.                 mirrors = self.get_mirrors(placeholders)
  285.                 
  286.                 if mirrors:
  287.                         allDefault = True
  288.                                 
  289.                         for mirror in mirrors:
  290.                                 p = placeholders[mirror]
  291.                                 p.add_mirror(self, not self.instant_update)
  292.                                 self.mirror_text[p.tabstop] = p.default
  293.                                 
  294.                                 if not p.default and not isinstance(p, PlaceholderExpand):
  295.                                         allDefault = False
  296.                         
  297.                         if allDefault:
  298.                                 self.update(None)
  299.                                 self.default = self.get_text() or None
  300.                 else:
  301.                         self.update(None)
  302.                         self.default = self.get_text() or None
  303.  
  304.                         if self.tabstop == -1:
  305.                                 self.done = True
  306.                 
  307.         def re_placeholder(self, m, formatter):
  308.                 if m.group(1):
  309.                         return '"$' + m.group(2) + '"'
  310.                 else:
  311.                         if m.group(3):
  312.                                 index = int(m.group(3))
  313.                         else:
  314.                                 index = int(m.group(4))
  315.                         
  316.                         return formatter(self.mirror_text[index])
  317.  
  318.         def remove_timeout(self):
  319.                 if self.timeout_id != None:
  320.                         gobject.source_remove(self.timeout_id)
  321.                         self.timeout_id = None
  322.                 
  323.         def install_timeout(self):
  324.                 self.remove_timeout()
  325.                 self.timeout_id = gobject.timeout_add(1000, self.timeout_cb)
  326.  
  327.         def timeout_cb(self):
  328.                 self.timeout_id = None
  329.                 
  330.                 return False
  331.         
  332.         def format_environment(self, text):
  333.                 return self.literal(text)
  334.  
  335.         def substitute(self, text, formatter = None):
  336.                 formatter = formatter or self.literal
  337.  
  338.                 # substitute all mirrors, but also environmental variables
  339.                 text = re.sub('(\\\\)?\\$({([0-9]+)}|([0-9]+))', lambda m: self.re_placeholder(m, formatter), 
  340.                                 text)
  341.                 
  342.                 return self.expand_environment(text)
  343.         
  344.         def run_update(self):
  345.                 text = self.substitute(self.cmd)
  346.                 
  347.                 if text:
  348.                         ret = self.expand(text)
  349.                         
  350.                         if ret:
  351.                                 self.update_leave_mirrors()
  352.                 else:
  353.                         ret = True
  354.                 
  355.                 return ret
  356.               
  357.         def update(self, mirror):
  358.                 text = None
  359.                 
  360.                 if mirror:
  361.                         self.mirror_text[mirror.tabstop] = mirror.get_text()
  362.                         
  363.                         # Check if all substitutions have been made
  364.                         for tabstop in self.mirror_text:
  365.                                 if tabstop == 0:
  366.                                         continue
  367.  
  368.                                 if self.mirror_text[tabstop] == None:
  369.                                         return False
  370.  
  371.                 return self.run_update()
  372.  
  373.         def expand(self, text):
  374.                 return True
  375.  
  376. # The shell placeholder executes commands in a subshell
  377. class PlaceholderShell(PlaceholderExpand):
  378.         def __init__(self, view, tabstop, begin, s):
  379.                 PlaceholderExpand.__init__(self, view, tabstop, begin, s)
  380.  
  381.                 self.shell = None
  382.                 self.remove_me = False
  383.  
  384.         def close_shell(self):
  385.                 self.shell.stdout.close()
  386.                 self.shell = None        
  387.         
  388.         def timeout_cb(self):
  389.                 PlaceholderExpand.timeout_cb(self)
  390.                 self.remove_timeout()
  391.                 
  392.                 if not self.shell:
  393.                         return False
  394.  
  395.                 gobject.source_remove(self.watch_id)
  396.                 self.close_shell()
  397.  
  398.                 if self.remove_me:
  399.                         PlaceholderExpand.remove(self)
  400.  
  401.                 message_dialog(None, gtk.MESSAGE_ERROR, 'Execution of the shell ' \
  402.                                 'command (%s) exceeds the maximum time, ' \
  403.                                 'execution aborted.' % self.command)
  404.                 
  405.                 return False
  406.         
  407.         def process_close(self):
  408.                 self.close_shell()
  409.                 self.remove_timeout()
  410.  
  411.                 self.set_text(str.join('', self.shell_output).rstrip('\n'))
  412.                 
  413.                 if self.default == None:
  414.                         self.default = self.get_text()
  415.                         self.leave()
  416.                         
  417.                 if self.remove_me:
  418.                         PlaceholderExpand.remove(self, True)
  419.                 
  420.         def process_cb(self, source, condition):
  421.                 if condition & gobject.IO_IN:
  422.                         line = source.readline()
  423.  
  424.                         if len(line) > 0:
  425.                                 try:
  426.                                         line = unicode(line, 'utf-8')
  427.                                 except:
  428.                                         line = unicode(line, locale.getdefaultlocale()[1], 
  429.                                                         'replace')
  430.  
  431.                         self.shell_output += line
  432.                         self.install_timeout()
  433.  
  434.                         return True
  435.  
  436.                 self.process_close()
  437.                 return False
  438.         
  439.         def literal(self, text):
  440.                 return '"' + re.sub('[\\\\"]', '\\\\\\1', text) + '"'
  441.         
  442.         def expand(self, text):
  443.                 self.remove_timeout()
  444.  
  445.                 if self.shell:
  446.                         gobject.source_remove(self.watch_id)
  447.                         self.close_shell()
  448.  
  449.                 popen_args = {
  450.                         'cwd'  : None,
  451.                         'shell': True,
  452.                         'env'  : os.environ,
  453.                         'stdout': subprocess.PIPE
  454.                 }
  455.  
  456.                 self.command = text
  457.                 self.shell = subprocess.Popen(text, **popen_args)
  458.                 self.shell_output = ''
  459.                 self.watch_id = gobject.io_add_watch(self.shell.stdout, gobject.IO_IN | \
  460.                                 gobject.IO_HUP, self.process_cb)
  461.                 self.install_timeout()
  462.                 
  463.                 return True
  464.                 
  465.         def remove(self, force = False):
  466.                 if not force and self.shell:
  467.                         # Still executing shell command
  468.                         self.remove_me = True
  469.                 else:
  470.                         if force:
  471.                                 self.remove_timeout()
  472.                                 
  473.                                 if self.shell:
  474.                                         self.close_shell()
  475.  
  476.                         PlaceholderExpand.remove(self, force)
  477.  
  478. class TimeoutError(Exception):
  479.         def __init__(self, value):
  480.                 self.value = value
  481.         
  482.         def __str__(self):
  483.                 return repr(self.value)
  484.  
  485. # The python placeholder evaluates commands in python
  486. class PlaceholderEval(PlaceholderExpand):
  487.         def __init__(self, view, tabstop, refs, begin, s, namespace):
  488.                 PlaceholderExpand.__init__(self, view, tabstop, begin, s)
  489.  
  490.                 self.fdread = 0
  491.                 self.remove_me = False
  492.                 self.namespace = namespace
  493.                 
  494.                 self.refs = []
  495.                 
  496.                 if refs:
  497.                         for ref in refs:
  498.                                 self.refs.append(int(ref.strip()))
  499.  
  500.         def get_mirrors(self, placeholders):
  501.                 mirrors = PlaceholderExpand.get_mirrors(self, placeholders)
  502.  
  503.                 if not self.ok:
  504.                         return None
  505.  
  506.                 for ref in self.refs:
  507.                         if ref in placeholders:
  508.                                 if ref not in mirrors:
  509.                                         mirrors.append(ref)
  510.                         else:
  511.                                 self.ok = False
  512.                                 return None
  513.  
  514.                 return mirrors
  515.  
  516.         def timeout_cb(self, signum = 0, frame = 0):
  517.                 raise TimeoutError, "Operation timed out (>2 seconds)"
  518.         
  519.         def install_timeout(self):
  520.                 if self.timeout_id != None:
  521.                         self.remove_timeout()
  522.                 
  523.                 self.timeout_id = signal.signal(signal.SIGALRM, self.timeout_cb)
  524.                 signal.alarm(2)
  525.                 
  526.         def remove_timeout(self):
  527.                 if self.timeout_id != None:
  528.                         signal.alarm(0)
  529.                         
  530.                         signal.signal(signal.SIGALRM, self.timeout_id)
  531.  
  532.                         self.timeout_id = None
  533.                 
  534.         def expand(self, text):
  535.                 self.remove_timeout()
  536.  
  537.                 text = text.strip()
  538.                 self.command = text
  539.  
  540.                 if not self.command or self.command == '':
  541.                         self.set_text('')
  542.                         return
  543.  
  544.                 text = "def process_snippet():\n\t" + "\n\t".join(text.split("\n"))
  545.                 
  546.                 if 'process_snippet' in self.namespace:
  547.                         del self.namespace['process_snippet']
  548.  
  549.                 try:
  550.                         exec text in self.namespace
  551.                 except:
  552.                         traceback.print_exc()
  553.  
  554.                 if 'process_snippet' in self.namespace:
  555.                         try:
  556.                                 # Install a sigalarm signal. This is a HACK to make sure 
  557.                                 # gedit doesn't get freezed by someone creating a python
  558.                                 # placeholder which for instance loops indefinately. Since
  559.                                 # the code is executed synchronously it will hang gedit. With
  560.                                 # the alarm signal we raise an exception and catch this
  561.                                 # (see below). We show an error message and return False.
  562.                                 # ___this is a HACK___ and should be fixed properly (I just 
  563.                                 # don't know how)                                
  564.                                 self.install_timeout()
  565.                                 result = self.namespace['process_snippet']()
  566.                                 self.remove_timeout()
  567.                         except TimeoutError:
  568.                                 self.remove_timeout()
  569.  
  570.                                 message_dialog(None, gtk.MESSAGE_ERROR, \
  571.                                 _('Execution of the python command (%s) exceeds the maximum ' \
  572.                                 'time, execution aborted.') % self.command)
  573.                                 
  574.                                 return False
  575.                         except Exception, detail:
  576.                                 self.remove_timeout()
  577.                                 
  578.                                 message_dialog(None, gtk.MESSAGE_ERROR, 
  579.                                 _('Execution of the python command (%s) failed: %s') % 
  580.                                 (self.command, detail))
  581.  
  582.                                 return False
  583.  
  584.                         if result == None:
  585.                                 # sys.stderr.write("%s:\n>> %s\n" % (_('The following python code, run in a snippet, does not return a value'), "\n>> ".join(self.command.split("\n"))))
  586.                                 result = ''
  587.  
  588.                         self.set_text(str(result))
  589.                 
  590.                 return True
  591.  
  592. # Regular expression placeholder
  593. class PlaceholderRegex(PlaceholderExpand):
  594.         def __init__(self, view, tabstop, begin, inp, pattern, substitution, modifiers):
  595.                 PlaceholderExpand.__init__(self, view, tabstop, begin, '')
  596.                 
  597.                 self.instant_update = True
  598.                 self.inp = inp
  599.                 self.pattern = pattern
  600.                 self.substitution = substitution
  601.                 
  602.                 self.init_modifiers(modifiers)
  603.         
  604.         def init_modifiers(self, modifiers):
  605.                 mods = {'I': re.I,
  606.                         'L': re.L,
  607.                         'M': re.M,
  608.                         'S': re.S,
  609.                         'U': re.U,
  610.                         'X': re.X}
  611.                 
  612.                 self.modifiers = 0
  613.  
  614.                 for modifier in modifiers:
  615.                         if modifier in mods:
  616.                                 self.modifiers |= mods[modifier]
  617.  
  618.         def get_mirrors(self, placeholders):
  619.                 mirrors = self.find_mirrors(self.pattern, placeholders) + self.find_mirrors(self.substitution, placeholders)
  620.  
  621.                 if isinstance(self.inp, int):
  622.                         if self.inp not in placeholders:
  623.                                 self.ok = False
  624.                                 return None
  625.                         elif self.inp not in mirrors:
  626.                                 mirrors.append(self.inp)
  627.  
  628.                 return mirrors
  629.  
  630.         def literal(self, s):
  631.                 return re.escape(s)
  632.  
  633.         def get_input(self):
  634.                 if isinstance(self.inp, int):
  635.                         return self.mirror_text[self.inp]
  636.                 elif self.inp in os.environ:
  637.                         return os.environ[self.inp]
  638.                 else:
  639.                         return ''
  640.         
  641.         def run_update(self):
  642.                 pattern = self.substitute(self.pattern)
  643.                 substitution = self.substitute(self.substitution, SubstitutionParser.escape_substitution)
  644.                 
  645.                 if pattern:
  646.                         return self.expand(pattern, substitution)
  647.                 
  648.                 return True
  649.         
  650.         def expand(self, pattern, substitution):
  651.                 # Try to compile pattern
  652.                 try:
  653.                         regex = re.compile(pattern, self.modifiers)
  654.                 except re.error, message:
  655.                         sys.stderr.write('Could not compile regular expression: %s\n%s\n' % (pattern, message))
  656.                         return False
  657.                 
  658.                 inp = self.get_input()
  659.                 match = regex.search(inp)
  660.                 
  661.                 if not match:
  662.                         self.set_text(inp)
  663.                 else:
  664.                         groups = match.groupdict()
  665.                         
  666.                         idx = 0
  667.                         for group in match.groups():
  668.                                 groups[str(idx + 1)] = group
  669.                                 idx += 1
  670.  
  671.                         groups['0'] = match.group(0)
  672.  
  673.                         parser = SubstitutionParser(substitution, groups)
  674.                         self.set_text(parser.parse())
  675.                 
  676.                 return True
  677. # ex:ts=8:et:
  678.